//
//  Constructors.c
//  Wood
//
//  Created by Wayne on 9/10/14.
//  Copyright (c) 2014 Wayne. All rights reserved.
//

#include <stdlib.h>
#include "Arch.h"
#include "Functions.h"

static Expression *allocExpression(ExpressionType type) {
    Expression *expr;
    expr = malloc(sizeof(Expression));
    expr->type = type;
    return expr;
}

Expression *createAssignExpression(char *variable, Expression *operand) {
    Expression *expr;
    expr = allocExpression(WdAssignExpression);
    expr->u.assignExpression = malloc(sizeof(AssignExpression));
    expr->u.assignExpression->variable = variable;
    expr->u.assignExpression->operand = operand;
    return expr;
}

static Expression *convertValueToExpression(Value *v) {
    Expression *expr;
    if (v->type == WdIntValue) {
        expr = allocExpression(WdIntExpression);
        expr->u.intValue = v->u.intValue;
    } else if (v->type == WdDoubleValue) {
        expr = allocExpression(WdDoubleExpression);
        expr->u.doubleValue = v->u.doubleValue;
    } else if (v->type == WdBoolValue) {
        expr = allocExpression(WdBoolExpression);
        expr->u.boolValue = v->u.boolValue;
    } else {
        /* TODO: compile error - bad operator */
    }
    return expr;
}

Expression *createBoolExpression(BOOL boolValue) {
    Expression *expr;
    expr = allocExpression(WdBoolExpression);
    expr->u.boolValue = boolValue;
    return expr;
}

Expression *createIntExpression(int intValue) {
    Expression *expr;
    expr = allocExpression(WdIntExpression);
    expr->u.intValue = intValue;
    return expr;
}

Expression *createDoubleExpression(double doubleValue) {
    Expression *expr;
    expr = allocExpression(WdDoubleExpression);
    expr->u.doubleValue = doubleValue;
    return expr;
}

Expression *createStringExpression(String *stringValue) {
    Expression *expr;
    expr = allocExpression(WdStringExpression);
    expr->u.stringValue = stringValue;
    return expr;
}

Expression *createBinaryExpression(ExpressionType operator, Expression *left, Expression *right) {
    if ((left->type == WdIntExpression || left->type == WdDoubleExpression) &&
        (right->type == WdIntExpression || right->type == WdDoubleExpression)) {
        Value v;
        v = evalBinaryExpression(NULL, operator, left, right);
        return convertValueToExpression(&v);
    } else {
        Expression *expr;
        expr = allocExpression(operator);
        expr->u.binaryExpression = malloc(sizeof(BinaryExpression));
        expr->u.binaryExpression->left = left;
        expr->u.binaryExpression->right = right;
        return expr;
    }
}

Expression *createIdentifierExpression(char *identifier) {
    Expression *expr;
    expr = allocExpression(WdIdentifierExpression);
    expr->u.identifier = identifier;
    return expr;
}

Expression *createMinusExpression(Expression *operand) {
    if (operand->type == WdIntExpression || operand->type == WdDoubleExpression) {
        Value v;
        v = evalMinusExpression(NULL, operand);
        return convertValueToExpression(&v);
    } else {
        Expression *expr;
        expr = allocExpression(WdMinusExpression);
        expr->u.minusExpression = operand;
        return expr;
    }
}

Expression *createFunctionCallExpression(char *identifier, ArgumentList *argument) {
    Expression *expr;
    expr = allocExpression(WdFunctionCallExpression);
    expr->u.functionCallExpression = malloc(sizeof(FunctionCallExpression));
    expr->u.functionCallExpression->identifier = identifier;
    expr->u.functionCallExpression->argument = argument;
    return expr;
}

static Statement *allocStatement(StatementType type) {
    Statement *statement;
    statement = malloc(sizeof(Statement));
    statement->type = type;
    return statement;
}

Statement *createFunctionDefinitionStatement(char *identifier, ParameterList *parameter, Block *block) {
    Statement *stm;
    stm = allocStatement(WdFunctionDefinitionStatement);
    stm->u.functionDefinitionStatement = malloc(sizeof(FunctionDefinitionStatement));
    stm->u.functionDefinitionStatement->identifier = identifier;
    stm->u.functionDefinitionStatement->parameter = parameter;
    stm->u.functionDefinitionStatement->block = block;
    return stm;
}

Statement *createReturnStatement(Expression *expr) {
    Statement *stm;
    stm = allocStatement(WdReturnStatement);
    stm->u.returnStatement = malloc(sizeof(ReturnStatement));
    stm->u.returnStatement->returnExpression = expr;
    return stm;
}